/* $RCSFile: PaymentGtwBase.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/AddonNice.ECommerce.BankGateway/PaymentGtwBase.cs $
 * $log$
 * Revision 8 2010/08/09 10:07:05  christian.surieux
 *   Added Log comment to all cs files
 */

using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Specialized;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Security.Cryptography;
using System.Web;
using System.Text;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Xml;
using System.Xml.Serialization;
using System.Globalization;
using System.Net;
using System.IO;

using AddonNice.Diagnostics;

using Trace2    =   System.Diagnostics.Trace;

namespace AddonNice.ECommerce.Gateways.Payment
{
	/// <summary>
	/// PaymentGtwBase is an abstract class used to build up
	/// custom gateway solutions for manage communication
	/// with secure Credit bank servers
	/// </summary>
	public abstract class PaymentGtwBase : GtwBase
	{

		#region Fields from EMerchantsData
		
		private Guid	_MerchantID						=	Guid.Empty;
		private int		_PortalID						=	0;
		private string	_MerchantEmail					=	string.Empty;
		private string	_TechnicalEmail					=	string.Empty;
		private string	_OkUrl			                =	string.Empty;
		private string	_NotOkUrl			            =	string.Empty;
		private string	_PaymentNotificationUrl	        =	string.Empty;
		private string	_Image					        =	string.Empty;
		private string	_Comment				        =	string.Empty;

		#endregion
		
		#region Properties
		
		string	_ISOCurrencySymbol	=	"EUR";
		public string ISOCurrencySymbol 
		{
			get 
			{
				return _ISOCurrencySymbol;
			}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose)
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase ISOCurrencySymbol SET value: {0}",value),Gtw2TraceSwitch.Info);
				if ( !string.IsNullOrEmpty(value) )
					_ISOCurrencySymbol = value;
			}
        }

        #region GtwBase overrides
        
        /// <summary>
		/// Purpose: Property to access the MerchantID field.
		/// Note that this is the AddonNice internal MerchandID, as opposed to the Merchant_id used by Sherlocks
		/// </summary>
		public override Guid MerchantID 
		{
			get 
			{
				return _MerchantID;
			}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose)
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase MerchandID SET value: {0}",value),Gtw2TraceSwitch.Info);
				_MerchantID = value;
			}
		}
		
		private NameValueCollection m_customSettings = new NameValueCollection();
		/// <summary>
		/// Custom Settings
		/// </summary>
		public override NameValueCollection CustomSettings
		{
			get {return m_customSettings;}
		}

        #endregion GtwBase overrides

        private	int		_TransacID						=-1;
		/// <summary>
		/// Purpose: Property to access the MerchantID field.
		/// </summary>
		public int TransacID 
		{
			get 
			{
				return _TransacID;
			}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose)
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[I]PaymentGtwBase TransacID SET value: {0}",value),Gtw2TraceSwitch.Info);
				_TransacID = value;
			}
		}

		/// <summary>
		/// Purpose: Property to access the PortalID field.
		/// </summary>
		public int PortalID 
		{
			get 
			{
				return _PortalID;
			}
			set 
			{
				_PortalID = value;
			}
		}
		
		/// <summary>
		/// Purpose: Property to access the MerchantEmail field.
		/// </summary>
		public string MerchantEmail 
		{
			get 
			{
				return _MerchantEmail;
			}
			set 
			{
				if ( value == null )
					value	=	string.Empty;
				_MerchantEmail = value;
			}
		}
		
		/// <summary>
		/// Purpose: Property to access the TechnicalEmail field.
		/// </summary>
		public string TechnicalEmail 
		{
			get 
			{
				return _TechnicalEmail;
			}
			set 
			{
				if ( value == null )
					value	=	string.Empty;
				_TechnicalEmail = value;
			}
		}

		private string TranformUrl(string MUrl)
		{
			string	val	=	MUrl;
			try
			{
				if ( !string.IsNullOrEmpty(MUrl) ) 
				{
				    if ( Gtw2TraceSwitch.TraceVerbose)
                        Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase TransformUrl BEG Url: {0}",MUrl),Gtw2TraceSwitch.Info);
					if ( MUrl.StartsWith("~/") )
					{
						val			=	HttpContext.Current.Request.Url.Scheme+"://"+HttpContext.Current.Request.Url.Authority+MUrl.Substring(1);
					}
					else if ( MUrl.StartsWith("/"))
					{
						val			=	HttpContext.Current.Request.Url.Scheme+"://"+HttpContext.Current.Request.Url.Authority+MUrl;
					}
				    if ( Gtw2TraceSwitch.TraceVerbose)
                        Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase TransformUrl Val: {0}",val),Gtw2TraceSwitch.Info);
					Uri Add		=	new Uri(val);
					string sh	=	Add.Scheme+"://";
					if ( !val.StartsWith(sh+HttpContext.Current.Request.Url.Authority) )
					{
						val		=	sh+HttpContext.Current.Request.Url.Authority;
						if ( HttpContext.Current.Request.Url.Authority == "localhost" )
						{
							for (int i=0 ; i < HttpContext.Current.Request.Url.Segments.GetUpperBound(0) && i < 2 ; i++ )
							{
								val		=	val+HttpContext.Current.Request.Url.Segments[i];
							}
						}
						if ( val.EndsWith("/") && Add.PathAndQuery.StartsWith("/") )
							val	+=	Add.PathAndQuery.Substring(1);
						else	val	+=	Add.PathAndQuery;
						Add		=	new Uri(val);
					}
					val = Add.ToString(); 
				}
			}
			catch(Exception ex )
			{
				if ( Gtw2TraceSwitch.TraceError)
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase TransformUrl ex: {0}",ex),Gtw2TraceSwitch.Info);
                throw;
			}
			if ( Gtw2TraceSwitch.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase TranformUrl string MUrl: {0}, Val: {1} ",MUrl,val),Gtw2TraceSwitch.Info);
			return val;
		}
		public string OkUrl 
		{
			get 
			{
				return TranformUrl(_OkUrl);
			}
			set 
			{
				if ( value == null )
					value	=	string.Empty;
				_OkUrl = value;
			}
		}

		public string NotOkUrl
		{
			get 
			{
				return TranformUrl(_NotOkUrl);
			}
			set 
			{
				if ( value == null )
					value	=	string.Empty;
				_NotOkUrl = value;
			}
		}

		public string PaymentNotificationUrl
		{
			get 
			{
				return  TranformUrl(_PaymentNotificationUrl );
			}
            set 
            {
                _PaymentNotificationUrl = value == null ? String.Empty : value;
            }
		}


		public string Image
		{
			get 
			{
				return _Image;
			}
			set 
			{
				if ( value == null )
					value	=	string.Empty;
				_Image = value;
			}
		}

		public string Comment
		{
			get 
			{
				return _Comment;
			}
			set 
			{
				if ( value == null )
					value	=	string.Empty;
				_Comment = value;
			}
		}

        /// <summary>
        /// Only for Sherlocks
        /// </summary>
		public virtual string MerchantCountry
        {
            get
            {
                return string.Empty;
            }
            set
            { }
        }
        
        /// <summary>
        /// Used to check associated provider parameters
        /// </summary>
        public abstract bool IsProviderOk
        { get; }
        
        
        /// <summary>
		/// For Payments
		/// </summary>
		public abstract int TransactionTypeID
		{
			get;
		}
		
		/// <summary>
		/// paypal->txn_id  sherlock ->authorisation_id
		/// </summary>
		public abstract string MerchantTransacID
		{
			get;
		}
		public abstract int PendingReason
		{
			get;
		}

		/// <summary>
		/// Paypal-> aucun sherlock->bank_response_code
		/// </summary>
		public abstract int BankResponseCode
		{
			get;
		}
		
        /// <summary>
        /// Paypal->first_name Sherlock->aucun
        /// </summary>
		public abstract string FirstName
		{
			get;
		}
		
        /// <summary>
        /// Paypal->last_name Sherlock->customer_id (we must send it)
        /// </summary>
		public abstract string LastName
		{
			get;
		}

		/// <summary>
		/// Paypal->payer_email Sherlock->customer_email(we must send it)
		/// </summary>
		public abstract string Email
		{
			get;
		}
		
		/// <summary>
		/// sherlock->card_number Paypal->aucun
		/// </summary>
		public abstract string CardNumber
		{
			get;
		}

		private bool m_testMode = false;
		
        /// <summary>
		/// If true Gateway runs in test mode.
		/// Some Gateways could have not a test mode.
		/// </summary>
		public bool TestMode
		{
			get {return m_testMode;}
			set {m_testMode = value;}
		}

		private string m_merchantP = string.Empty;
		
        /// <summary>
		/// A code or 4 alphanumeric characters to indicate the vendor
		/// </summary>
		public string MerchantP
		{
			get 
			{
				return m_merchantP;
			}
			set 
			{
				m_merchantP = value;
			}
		}

		private Guid m_orderID;
		/// <summary>
		/// Current order ID, could be assigned or auto-generated
		/// </summary>
		public Guid OrderID
		{
			get 
			{
				return m_orderID;
			}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose)
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase OrderID SET value: {0}",value),Gtw2TraceSwitch.Info);
				m_orderID = value;
			}
		}

		public virtual string RawTransac
		{
			get
			{
				return string.Empty;
			}
			set
			{}
		}


		private decimal m_Tot2Check=0;
		/// <summary>
		/// Price without VAT expenses, shipping and discount to pay
		/// </summary>
		protected virtual decimal Tot2Check
		{
			get {return m_Tot2Check;}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Tot2Check SET value: {0} TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				m_Tot2Check	=	value;
			}
		}

		public virtual bool CheckTotal(decimal total)
		{
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase CheckTotal total: {0}, Tot2Check: {1}, TransacID: {2}",total,Tot2Check,TransacID),Gtw2TraceSwitch.Info);
				return Tot2Check == total;
				}
		}

		public virtual decimal Total
		{
			get 
			{
				decimal tot				=	Price+Taxes+ShippingPrice+Expenses-Discount;
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Total GET : {0}, TransacID: {1}",tot,TransacID),Gtw2TraceSwitch.Info);
				return tot;
			}
		}

		private decimal m_price=0;
		/// <summary>
		/// Price without VAT expenses, shipping and discount to pay
		/// </summary>
		public decimal Price
		{
			get {return m_price;}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Price SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				m_price = value;
			}
		}

		private decimal m_Taxes		=	0;
		/// <summary>
		/// Taxes to pay
		/// </summary>
		public decimal Taxes
		{
			get {return m_Taxes;}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Taxes SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				m_Taxes = value;
			}
		}

		private decimal m_ShippingPrice=0;
		/// <summary>
		/// Shipping to pay
		/// </summary>
		public decimal ShippingPrice
		{
			get {return m_ShippingPrice;}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase ShippingPrice SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				m_ShippingPrice = value;
			}
		}

		private decimal m_Expenses=0;
		/// <summary>
		/// Expenses to pay
		/// </summary>
		public virtual decimal Expenses
		{
			get 
			{
				return m_Expenses;
			}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Expenses SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				m_Expenses = value;
			}
		}

		private decimal m_Discount=0;
		/// <summary>
		/// Discount on order
		/// </summary>
		public virtual decimal Discount
		{
			get 
			{
				return m_Discount;
			}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Discount SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				m_Discount = value;
			}
		}

		private string m_buyerEmail;
		/// <summary>
		/// Email of the buyer
		/// </summary>
		public string BuyerEmail
		{
			get
			{
				return m_buyerEmail;
			}
			set 
			{	
				//Checks if Email is specified and valid
				m_buyerEmail = CheckEmail(value);
			}
		}
		private string _BuyerAddress	=	string.Empty;
		public string BuyerAddress
		{
			get
			{
				return _BuyerAddress;
			}
			set 
			{	
				_BuyerAddress = value;
			}
		}
		private string _BuyerCity	=	string.Empty;	
		public string BuyerCity	
		{
			get
			{
				return _BuyerCity;
			}
			set 
			{	
				_BuyerCity = value;
			}
		}
		private string _BuyerZip	=	string.Empty;
		public string BuyerZip
		{
			get
			{
				return _BuyerZip;
			}
			set 
			{	
				_BuyerZip = value;
			}
		}
		private string _BuyerCountry	=	string.Empty;
		public string BuyerCountry
		{
			get
			{
				return _BuyerCountry;
			}
			set 
			{	
				_BuyerCountry = value;
			}
		}

		private string m_buyerName;
		/// <summary>
		/// Full Name of the buyer, must be free nof any special char like space, ':','|', ';'
		/// </summary>
		public string BuyerName
		{
			get 
			{
				return m_buyerName;
			}
			set 
			{
				// Sherlocks does not support spaces and special cars like |;:
				m_buyerName =	value.Replace(' ','_');
				m_buyerName	=	m_buyerName.Replace(':','_');
				m_buyerName	=	m_buyerName.Replace('|','_');
				m_buyerName	=	m_buyerName.Replace(';','_');
			}
		}

		private Guid m_UserID;
	
		public Guid UserID
		{
			get 
			{
				return m_UserID;
			}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase UserID SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				m_UserID = value;
			}
		}

				
		/// <summary>
		/// If valid reurn email, if not raise an exception
		/// </summary>
		private string CheckEmail(string settingName)
		{
			if (
				settingName == null || 
				settingName == string.Empty || 
				settingName.IndexOf('@') < 0 ||
				settingName.IndexOf('@') >= settingName.LastIndexOf('.')
				)
			{
                string msg  =   string.Format("[E]PaymentGtwBase CheckEMail failed email: '{0}', TransacID: {1}",settingName,TransacID);
				if ( Gtw2TraceSwitch.TraceError )
                    Trace2.WriteLine(msg,Gtw2TraceSwitch.Info);
				throw new ArgumentException(msg, settingName);
			}
			return settingName;
		}


		private string m_paymentType;
		/// <summary>
		/// Type of payment
		/// </summary>
		public string PaymentType
		{
			get {return m_paymentType;}
			set {m_paymentType = value;}
		}

		private string m_authCode;
		/// <summary>
		/// Authorization code assigned from the Credit Bank
		/// </summary>
		public string AuthCode
		{
			get 
			{
				return m_authCode;
			}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase AuthCode SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				m_authCode = value;
			}
		}

		private string m_transactionID	=	string.Empty;
		/// <summary>
		/// TransactionID code assigned from the Credit Bank
		/// Or internaly for the credit bank
		/// </summary>
		public virtual string TransactionID
		{
			get 
			{
				return m_transactionID;
			}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase TransactionID SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				if ( value != null )
					m_transactionID = value;
			}
		}

		/// <summary>
		/// Text of the submit button (for localization purpose)
		/// </summary>
		public string SubmitButtonText = "Submit";

		CultureInfo m_language = System.Threading.Thread.CurrentThread.CurrentUICulture;
		/// <summary>
		/// Gateway language
		/// </summary>
		public CultureInfo Language
		{
			get 
			{
				return m_language;
			}
			set 
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Langage SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				try
				{
				    m_language												=	value;
				    System.Threading.Thread.CurrentThread.CurrentUICulture	=	value;
				}
				catch(Exception ex)
				{
				    if ( Gtw2TraceSwitch.TraceError )
					    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase LanguageSET  value: {0}, TransacID: {1}, ex: {2}",value,TransacID,ex));
				}

			}
		}

		CultureInfo m_Culture = System.Threading.Thread.CurrentThread.CurrentCulture;
		/// <summary>
		/// Gateway language
		/// </summary>
		public CultureInfo Culture
		{
			get 
			{
				return m_Culture;
			}
			set 
			{
                if ( Gtw2TraceSwitch.TraceVerbose )
				    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Culture SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				try
				{
					m_Culture												=	value;
					System.Threading.Thread.CurrentThread.CurrentCulture	=	value;
				}
				catch(Exception ex)
				{
                    if ( Gtw2TraceSwitch.TraceError )
	    				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase Culture SET value: {0}, TransacID: {1}, ex: {2}",value,TransacID,ex));
				}
			}
		}

		private Stack LangStack	=	new Stack();
		protected void SaveLanguage()
		{
			if ( Gtw2TraceSwitch.TraceVerbose )
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase SaveLangage BEG TransacID: {0}",TransacID),Gtw2TraceSwitch.Info);
			try
			{
				CultureInfo[] ob	=	new CultureInfo[]{
									System.Threading.Thread.CurrentThread.CurrentUICulture,
									System.Threading.Thread.CurrentThread.CurrentCulture
														 };
				LangStack.Push(ob);
			}
			catch(Exception ex)
			{
                if ( Gtw2TraceSwitch.TraceError )
				    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase SaveLangage TransacID: {0}, ex: {1}",TransacID,ex));
                return;// should throw
			}
			if ( Gtw2TraceSwitch.TraceVerbose )
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase SaveLangage END Ok TransacID: {0}",TransacID),Gtw2TraceSwitch.Info);
		}
		protected void RestLanguage()
		{
			if ( Gtw2TraceSwitch.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase RestLangage BEG TransacID: {0}, UI: {1}, culture: {2}",
                    TransacID,
                    System.Threading.Thread.CurrentThread.CurrentUICulture.Name,
                    System.Threading.Thread.CurrentThread.CurrentCulture.Name),Gtw2TraceSwitch.Info);
			try
			{
				object ob			=	LangStack.Pop();
				CultureInfo[] Lang	=	(CultureInfo[])(ob);
				Language			=	Lang[0];
				Culture				=	Lang[1];
			}
			catch(Exception ex)
			{
				if ( Gtw2TraceSwitch.TraceError )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase RestLangage TransacID: {0}, ex: {1}",TransacID,ex),Gtw2TraceSwitch.Info);
                return; // should throw
			}
			if ( Gtw2TraceSwitch.TraceVerbose )
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase RestLangage END Ok TransacID: {0}",TransacID),Gtw2TraceSwitch.Info);
		}

        protected void SetLanguage()
		{
			if ( Gtw2TraceSwitch.TraceVerbose )
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase SetLangage BEG TransacID: {0}",TransacID),Gtw2TraceSwitch.Info);
			try
			{
				SaveLanguage();
				Language	=	new System.Globalization.CultureInfo("fr",false);
				Culture		=	new System.Globalization.CultureInfo("fr-FR",false);
			}
			catch(Exception ex)
			{
				if ( Gtw2TraceSwitch.TraceError )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase SetLangage TransacID: {0}, ex: {1}",TransacID,ex),Gtw2TraceSwitch.Info);
                return; // should throw
			}
			if ( Gtw2TraceSwitch.TraceVerbose )
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase SetLangage END Ok TransacID: {0}",TransacID),Gtw2TraceSwitch.Info);
	    }


		private string _Key2Check	=	string.Empty;
		/// <summary>
		/// Internal key to check in IPN and return from payment
		/// </summary>
		protected virtual string Key2Check
		{
			get
			{
				return _Key2Check;
			}
			set
			{
				if ( value != null )
				{
					if ( Gtw2TraceSwitch.TraceVerbose )
                        Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Key2Check SET  value: '{0}', len: {1}, TransacID: {2}",value,value.Length,TransacID),Gtw2TraceSwitch.Info);
					_Key2Check	=	value;
				}
			}
		}

		/// <summary>
		/// Property set from the ECommerceMerchant Account: if not zero used to calculated expenses from the total amount
		/// of the payment
		/// </summary>
		private decimal	_PercentExpenses	=	0;
		public decimal	PercentExpenses
		{
			get
			{
				return _PercentExpenses;
			}
			set
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase PercentExpenses SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				_PercentExpenses = value;
			}
		}

		/// <summary>
		/// Property set from the ECommerceMerchant Account: if not zero used to calculated expenses 
		/// as a fixed amount
		/// </summary>
		private decimal	_FixedExpenses	=	0;
		public decimal FixedExpenses
		{
			get
			{
				return _FixedExpenses;
			}
			set
			{
				if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase FixedExpenses SET value: {0}, TransacID: {1}",value,TransacID),Gtw2TraceSwitch.Info);
				_FixedExpenses = value;
			}
		}

		#endregion Properties

		/// <summary>
		/// If the gateway generates expenses we compute them here: called by checkout
		/// </summary>
        public virtual decimal ComputeExpenses(decimal totalAmount) 
        {
            try 
            {
                if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase ComputeExpenses totalAmount: '{0}', PercentExpenses: '{1}'",totalAmount,PercentExpenses),Gtw2TraceSwitch.Info);
                if (  PercentExpenses != 0)
                    Expenses = totalAmount * PercentExpenses / 100;
                else Expenses = FixedExpenses;
                if ( Gtw2TraceSwitch.TraceVerbose )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase ComputeExpenses END Expenses: {0}, TransacID: {1}", Expenses, TransacID),Gtw2TraceSwitch.Info);
                return Expenses;
            } 
            catch (Exception ex) 
            {
                if ( Gtw2TraceSwitch.TraceError )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase ComputeExpenses ex: {0}", ex));
                throw;
            }
        }

		/// <summary>
		/// Just before creating the payment form, extract some information from customer info
		/// </summary>
		protected virtual void GetCustInfo(Hashtable Cust)
		{
			object obj				=	Cust["LastName"];
			if ( obj != null )
				BuyerName			=	(string)obj;
			obj						=	Cust["EMail"];
			if ( obj != null )
				BuyerEmail			=	(string)obj;

			obj						=	Cust["Address1"];
			if ( obj != null )
				BuyerAddress		=	(string)obj;
			obj						=	Cust["City"];
			if ( obj != null )
				BuyerCity			=	(string)obj;
			obj						=	Cust["Zip"];
			if ( obj != null )
				BuyerZip			=	(string)obj;
			
			obj						=	Cust["Country"];
			if ( obj != null )
				BuyerCountry			=	(string)obj;

			}

		/// <summary>
		/// Gets the form for contacting the Credit bank gateway
		/// </summary>
		public abstract bool GetForm(System.Web.UI.Control panelSubmit,Hashtable Cust);

        /// <summary>
        /// Format the content to send to gateway as Html elements (hidden fields)
        /// </summary>
        public abstract string GetContent(Hashtable Cust);

        /// <summary>
		/// In charge of checking the keyfield sent with each transaction
		/// </summary>
		public virtual bool ReceiptOk
		{
			get
			{
				bool ret	= ( Key2Check == TransacKey2 );
                if ( Gtw2TraceSwitch.TraceVerbose )
    				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase ReceiptOk TransacID: {0}, Key2Check: '{1}' Ok: {2}",TransacID,Key2Check,ret),Gtw2TraceSwitch.Info);
				return ret;
			}
		}

		
		/// <summary>
		/// Called by Order.Finalize to decide next status Completed or Failed
		/// </summary>
		public virtual bool CheckStatus()
		{
			return true;
		}


		/// <summary>
		/// Called by Order.Finalize to decide if status should be changed to Completed or keep on Pending
		/// </summary>
		public virtual bool ShouldChangePendingStatus()
		{
			return true;
		}

		/// <summary>
		/// Called by Order.Finalize to find if OK has been sent from bank fo transaction
		/// </summary>
		public virtual bool IsPaymentCompleted()
		{
			return false;
		}

        /// <summary>
		/// Retrieve a parameters string encrypted with MAC code
		/// </summary>
		protected string GetHashMD5(string inputString)
		{
			// Get an ASCII encoder
			System.Text.ASCIIEncoding encoder = new ASCIIEncoding();

			// This is one implementation of the abstract class MD5.
			MD5 md5 = new MD5CryptoServiceProvider();
			byte[] result = md5.ComputeHash(encoder.GetBytes(inputString));

			// Get MD5 Hash
			string md5Result = Convert.ToBase64String(result);

			// Output result for diagnostic purposes (debug mode only)
            if ( Gtw2TraceSwitch.TraceVerbose )
				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase GetHashMD5 inputString: {0}, md5Result: '{1}'",inputString,md5Result),Gtw2TraceSwitch.Info);
			return md5Result;
		}

		private static readonly byte[] encryptionKeyBytes =
			new byte[] { 0x12, 0x46, 0x36, 0x32, 0x38, 0x33, 0x46, 0x36 };

		/// <summary>
		/// Internal usage for crypting keys used to validate origin of transactions
		/// </summary>
		private string GenerateEncryptedKey(string inputString) 
		{
            if ( Gtw2TraceSwitch.TraceVerbose )
			    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase GenerateEncryptedKey BEG TransacID: {0}, inputString: '{1}'",TransacID,inputString),Gtw2TraceSwitch.Info);
            byte[] result						        =	null;
            // 2010
            MemoryStream InputMemStr                    =   null;
            MemoryStream MemStr                         =   null;
            CryptoStream cryptostream                   =   null;
            try
            {
                InputMemStr                             =   new MemoryStream();
                StreamWriter writer                     =   new StreamWriter(InputMemStr); // defaults to UTF8
                writer.Write(inputString);
                writer.Flush();
                InputMemStr.Seek(0,SeekOrigin.Begin);
                DESCryptoServiceProvider DES            =   new DESCryptoServiceProvider();
                DES.Key = encryptionKeyBytes;
                DES.IV = encryptionKeyBytes;
                ICryptoTransform desencrypt             =   DES.CreateEncryptor();
                MemStr                                  =   new MemoryStream();
                cryptostream                            =   new CryptoStream(MemStr,desencrypt,CryptoStreamMode.Write);
                cryptostream.Write(InputMemStr.GetBuffer(),0,(int)InputMemStr.Length);
                cryptostream.FlushFinalBlock();
                result                                  =   MemStr.GetBuffer();

            }
            catch ( Exception ex )
            {
                if ( Gtw2TraceSwitch.TraceError )
                    Trace2.WriteLine(string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase GenerateEncryptedKey ex: {0}",ex));
                throw;
            }
            finally
            {
                if ( InputMemStr != null )
                    InputMemStr.Close();
                if ( MemStr != null )
                    MemStr.Close();
                if ( cryptostream != null )
                    cryptostream.Close();
            }
            string b64Result            =   HttpServerUtility.UrlTokenEncode(result);
            if ( Gtw2TraceSwitch.TraceVerbose )
			    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase GenerateEncryptedKey END result: '{0}', len: {1}",b64Result,b64Result.Length),Gtw2TraceSwitch.Info);
			return	b64Result;
		}

		private string RevertEncryptedKey(string inputString) 
		{
            if ( Gtw2TraceSwitch.TraceVerbose )
			    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase RevertEncryptedKey BEG TransacID: {0} inputstring: '{1}', len: {2}",TransacID,inputString,inputString.Length),Gtw2TraceSwitch.Info);
            // 2010
            string sResult						        =	string.Empty;
            MemoryStream MemStr                         =   null;
            MemoryStream OutputMemStr                   =   null;
            StreamReader reader                         =   null;
        	CryptoStream cryptostreamDecr               =   null;
            try 
			{
			    byte[] contents1					    =	HttpServerUtility.UrlTokenDecode(inputString);
                DESCryptoServiceProvider DES            =   new DESCryptoServiceProvider();
		        DES.Key							        =	encryptionKeyBytes;
			    DES.IV							        =	encryptionKeyBytes;
	            ICryptoTransform desdecrypt             =   DES.CreateDecryptor();
                MemStr                                  =   new MemoryStream(contents1);
                MemStr.Position                         =   0;
        	    cryptostreamDecr                        =   new CryptoStream(MemStr, desdecrypt,CryptoStreamMode.Read);
                byte[] content                          =   new byte[contents1.Length];
                int readCnt                             =   cryptostreamDecr.Read(content,0,contents1.Length);

                OutputMemStr                            =   new MemoryStream(content,0,readCnt);
                reader                                  =   new StreamReader( OutputMemStr );// defaults to UTF8
                sResult						            =	reader.ReadToEnd();
			}
            catch(Exception ex)
			{
                if ( Gtw2TraceSwitch.TraceError )
				    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase RevertEncryptedKey ex : {0}",ex));
                throw;
			}
            finally
            {
                if ( cryptostreamDecr != null )
                    cryptostreamDecr.Close();
                if ( reader != null )
                    reader.Close();
                if ( MemStr != null )
                    MemStr.Close();
                if ( OutputMemStr != null )
                    OutputMemStr.Close();
            }
            if ( Gtw2TraceSwitch.TraceVerbose )
			    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase RevertEncryptedKey END result: '{0}', len: {1}",sResult,sResult.Length),Gtw2TraceSwitch.Info);
			return	sResult;
            /*
			// check for separator escape sequence
			//string	inputstr					=	inputString.Replace("####","/");
			// 3/2010 byte[] contents1					=	Convert.FromBase64String(inputstr);
            int cnt								=	contents1.Length;
			if ( cnt < 8 )
				cnt		                        =	8;
			else 
			{
				int nb	                        =	contents1.Length/8;
				cnt		                        =	8*(nb);
				if ( cnt < contents1.Length )
					cnt	                        +=	8;
			}
			byte[] contents						=	new byte [cnt];
			Array.Copy(contents1,0,contents,0,contents1.Length);

			int sz								=	contents.Length;
			byte[] result						=	new byte[sz];

			try 
			{
				DESCryptoServiceProvider des	=	new DESCryptoServiceProvider();
				des.Padding						=	PaddingMode.None;
				des.Key							=	encryptionKeyBytes;
				des.IV							=	encryptionKeyBytes;
				ICryptoTransform desDecryptor	=	des.CreateDecryptor();
				int pos							=	0;
				int size						=	(contents.Length/8)*8;
				int len							=	desDecryptor.TransformBlock(contents,pos,contents.Length-pos,result,pos);
				pos								+=	len;
				size							=	((contents.Length-pos)/8)*8;
				while ( len > 0 && size >= 8  )
				{
					len							=	desDecryptor.TransformBlock(contents,pos,contents.Length-pos,result,pos);
					pos							+=	len;
					size						=	((contents.Length-pos)/8)*8;
				}
				size							=	contents.Length-pos;
				if ( size > 0 )
					desDecryptor.TransformFinalBlock(contents,pos,size);
			}
			catch(Exception ex)
			{
                if ( Gtw2TraceSwitch.TraceError )
				    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase RevertEncryptedKey ex : {0}",ex));
                throw;
			}
			string sResult						=	Encoding.ASCII.GetString(result);
             * */
		}


		/// <summary>
		/// Generate a trace Key for each transaction based on transacID merchantID and OrderID
		/// </summary>
		public	string TransacKey
		{
			get
			{
				SetLanguage();
				string basestr	=	string.Format("{0}/{1}/{2}/{3}/{4}",new object[]{TransacID,MerchantID,OrderID,Total.ToString(CultureInfo.InvariantCulture),UserID});
                if ( Gtw2TraceSwitch.TraceVerbose )
    				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Transackey BaseStr: '{0}', TransacID: {1}",basestr,TransacID),Gtw2TraceSwitch.Info);
				string	str		=	GenerateEncryptedKey(basestr);
				RestLanguage();
				return str;
			}
		}

		public	string TransacKey2
		{
			get
			{
				SetLanguage();
				string basestr	=	string.Format("{0}/{1}/{2}/{3}/{4}",new object[]{TransacID,MerchantID,OrderID,Tot2Check.ToString(CultureInfo.InvariantCulture),UserID});
                if ( Gtw2TraceSwitch.TraceVerbose )
    				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Transackey2 BaseStr: '{0}', TransacID: {1}",basestr,TransacID),Gtw2TraceSwitch.Info);
				string	str		=	GenerateEncryptedKey(basestr);
				RestLanguage();
				return str;
			}
		}

		/// <summary>
		/// return a mark inserted in each transaction to check returned values from IPN or other
		/// </summary>
		public	string Gtw2Mark
		{
			get
			{
                if ( Gtw2TraceSwitch.TraceVerbose )
    				Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase Gtw2Mark TransacID: {0}, MerchantID: {1}, OrderID: {2}, UserID: {3}",
                        new object[]{TransacID,MerchantID,OrderID,UserID}),Gtw2TraceSwitch.Info);
				return string.Format("{0}/{1}/{2}/{3}/{4}",new object[]{TransacID,MerchantID,OrderID,UserID,TransacKey});
			}
		}
		
		/// <summary>
		/// Static method provided for access from IPN receipt or return from paiment to decode the crypted key and retreive the MerchantID
		/// </summary>
		public static string[] DecodeMark(string custom)
		{
			string[] CodeStr			=	custom.Split(new char[]{'/'});
            int upperBnd                =   CodeStr.GetUpperBound(0);
			if (  upperBnd < 4 )
			{
                string msg  =   string.Format("[E]PaymentGtwBase DecodeMark Bad Mark received from server: '{0}', GetUpperBound: {1}",custom,upperBnd);
                if ( Gtw2TraceSwitch.TraceError )
    				Trace2.WriteLine(msg,Gtw2TraceSwitch.Info);
				throw (new Exception(msg));
			}
            if ( Gtw2TraceSwitch.TraceVerbose )
    			Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase DecodeMark : {0},{1},{2},{3}",
                    new object[]{CodeStr[0],CodeStr[1],CodeStr[2],CodeStr[3]}),Gtw2TraceSwitch.Info);
			return CodeStr;
		}
		
		private string[] DecodeKey2Check(string custom)
		{
			string[] CodeStr			=	custom.Split(new char[]{'/'});
			if ( CodeStr.GetUpperBound(0) < 4 )
			{
                string msg  =   string.Format("[E]PaymentGtwBase DecodeKey2Check Bad Mark received from server: '{0}', GetUpperBound: {1}",custom,CodeStr.GetUpperBound(0));
                if ( Gtw2TraceSwitch.TraceError )
    				Trace2.WriteLine(msg,Gtw2TraceSwitch.Info);
				return new string[0];
				// don't beak all throw(new Exception("DecodeKey2Check Bad Mark received from server :"+custom));
			}
            if ( Gtw2TraceSwitch.TraceVerbose )
    			Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase DecodeKey2Check : {0},{1},{2},{3},{4}",new object[]{CodeStr[0],CodeStr[1],CodeStr[2],CodeStr[3],CodeStr[4]}),Gtw2TraceSwitch.Info);
			return CodeStr;
		}

		/// <summary>
		/// Gets a key pair value as hidden input field 
		/// </summary>
		protected LiteralControl GetHidden(string name, string val, bool required)
		{
			if ( string.IsNullOrEmpty(val) )
			{
				if( required )
				{
					string msg  =   string.Format("[V]PaymentGtwBase GetHidden no value Name: {0}, TransacID: {1}",name,TransacID);
                    if ( Gtw2TraceSwitch.TraceError )
    				    Trace2.WriteLine(msg,Gtw2TraceSwitch.Info);
					throw(new ArgumentOutOfRangeException(name, msg));
				}
				return new LiteralControl(string.Format("<input type='hidden' name='{0}'>",name));
			}
			LiteralControl h = new LiteralControl(string.Format("<input type='hidden' name='{0}' value='{1}'>",name,val));
			return h;            
		}

		protected void InsertHidden(HtmlTextWriter wr,string name, string val, bool required)
		{
			if ( val == null || val == string.Empty )
			{
				if( required )
				{
					string msg  =   string.Format("[V]PaymentGtwBase InsertHidden no value Name: {0}, TransacID: {1}",name,TransacID);
                    if ( Gtw2TraceSwitch.TraceError )
    				    Trace2.WriteLine(msg,Gtw2TraceSwitch.Info);
					throw(new ArgumentOutOfRangeException(name, msg));
				}
				return;
			}
			wr.AddAttribute(HtmlTextWriterAttribute.Type,"HIDDEN",true);
			wr.AddAttribute(HtmlTextWriterAttribute.Name,name,true);
			wr.AddAttribute(HtmlTextWriterAttribute.Value,val,true);
			wr.RenderBeginTag(HtmlTextWriterTag.Input);
			wr.RenderEndTag();
		}

		/// <summary>
		/// Gets a key pair value as parameter suitable for Http requests
		/// </summary>
		protected string GetUrlParameter(string name, string value, bool required)
		{
			if ( value == null || value == string.Empty )
			{
				if(required)
				{
					string msg  =   string.Format("[V]PaymentGtwBase GetUrlParameter no value Name: {0}, TransacID: {1}",name,TransacID);
                    if ( Gtw2TraceSwitch.TraceError )
    				    Trace2.WriteLine(msg,Gtw2TraceSwitch.Info);
					throw(new ArgumentOutOfRangeException(name, msg));
				}
				else
				{
					return string.Empty;
				}
			}
			else
			{
				string h = string.Concat(name, "=", value, "&");
				return h;            
			}
		}
        
        public virtual bool Ok4Currency(string ISOCurrencySymbol)
        {
            return true;
        }

		/// <summary>
		/// Used to validate and decode information after a payment transaction: called for IPN or normal return
		/// </summary>
		public virtual void InitFromResponse(NameValueCollection Form,string custom)
		{
			string[] CodeStr					=	DecodeMark(custom);
			TransacID							=	int.Parse(CodeStr[0]);
			MerchantID							=	new Guid(CodeStr[1]);
			OrderID								=	new Guid(CodeStr[2]);
			UserID								=	new Guid(CodeStr[3]);
			Key2Check							=	CodeStr[4];
            string[] result						=   null;
			// we should get this.TransacID,this.MerchantID,this.OrderID,this.Total,this.UserID			
			try
			{
			    result						    =	DecodeKey2Check(RevertEncryptedKey(Key2Check));
				Tot2Check					    =	Convert.ToDecimal(result[3],CultureInfo.InvariantCulture);
				}
			catch(Exception exp)
			{
                if ( Gtw2TraceSwitch.TraceError )
				    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase InitFromResponse Converting crypted total ex: {0}", exp),Gtw2TraceSwitch.Info);
			}

			Type MyType							=	GetType();
		
            if ( Gtw2TraceSwitch.TraceVerbose )
    			Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]PaymentGtwBase InitFromResponse TransacID: {0} , MerchantID: {1}, OrderID: {2}, UserID: {3}, Key2Check: {4}",
                    new object[]{TransacID,MerchantID,OrderID,UserID,Key2Check}),Gtw2TraceSwitch.Info);
			foreach(string key in Form.Keys)
			{
				object ob						=	Form[key];
				if ( ob == null )
					continue;
				// Seach for a property with this name
				System.Reflection.PropertyInfo Mypropertyinfo = MyType.GetProperty(key);
				try
				{
					if ( Mypropertyinfo != null )
					{
						if ( Mypropertyinfo.PropertyType.IsArray )
							continue;
						// Use the SetValue method to change it.
						if ( Mypropertyinfo.CanWrite )
						{
							//If we find it we set it (we have to cast to proper type for non string values like booleans)
							Mypropertyinfo.SetValue(this, Convert.ChangeType(ob, ob.GetType()), null);
							continue;
						}
					}
					//If we do not find it we add to custom properties collection
					if ( ob is String )
						CustomSettings[key] = (string)ob;
				}
				catch(Exception exp)
				{
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase InitFromResponse gateway: {0} MerchantID: {1} Mypropertyinfo: {2}, ex: {3}",
                        Name,MerchantID,Mypropertyinfo,exp),Gtw2TraceSwitch.Info);
				}
			}
		}
		
		/// <summary>
		/// For debug only
		/// </summary>
		public override string ToString()
		{
			Type MyType							=	GetType();
			StringBuilder	sb					=	new StringBuilder();
			foreach( System.Reflection.PropertyInfo Mypropertyinfo in MyType.GetProperties())
			{
				try
				{
					if ( Mypropertyinfo.Name == "Item" )
						continue;
					if ( Mypropertyinfo.PropertyType.IsArray )
						continue;
					if ( Mypropertyinfo.CanRead)
					{
						sb.AppendFormat("'{0}'='{1}',\n",Mypropertyinfo.Name,Mypropertyinfo.GetValue(this,null));
					}
				}
				catch(Exception exp)
				{
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase ToString ex: {0}",exp));
				}
			}
			foreach(string key in CustomSettings)
			{
				try
				{
					sb.AppendFormat("'{0}'='{1}',\n",key,CustomSettings[key]);
				}
				catch(Exception exp)
				{
					Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]PaymentGtwBase ToString CustomSettings ex:{0}",exp));
				}

			}
			return sb.ToString();
		}

	}
}